﻿#include "crc.h"
#include "rs485_connect.h"

rs485_connect::rs485_connect(QObject* parent) : QObject {parent}
{
    //首先创建rs485通信的线程
    subThread = new QThread;

    //初始化报文
    //设备地址(站号)、功能码、起始地址高字节，起始地址低字节、读取寄存器数量高字节、读取寄存器数量低字节
    //CRC检验低字节、CRC校验高字节
    unsigned char hex[8] {0x01, 0x04, 0x00, 0x00, 0x00, 0x02};

    unsigned short crc;
    //遍历2次，生成4组不的报文
    for (int i = 0; i < 2; i++)
    {
        //修改设备地址(站号)，从设备管理界面进行操作
        hex[0] = i + 1;
        //对前6个字节进行校验,并返回一个16位的CRC校验码
        crc = CRC16(hex, 6);
        //分别去CRC的低、高字节
        hex[6] = static_cast<unsigned char>(crc);
        hex[7] = static_cast<unsigned char>(crc >> 8);
        //将hex转换成QbyteArray并存入readcommand[i]
        readCommand[i] = QByteArray((char*)hex, 8);
        //打印十六进制的字符，方便进行调试
        qDebug() << readCommand[i].toHex();

    }
    //在开启线程之前进行串口的初始化(@如何创建单一的线程程序)
    port = new QSerialPort;
    this->moveToThread(subThread);
    port->moveToThread(subThread);
    subThread->start();
}

void rs485_connect::initPort(const QString& portName)
{
    if(this->port->isOpen())
    {
        this->port->clear();//清除串口的缓冲区数据，终止读写操作
        this->port->close();//关闭串口
    }
    //设置打开的串口名称
    this->port->setPortName(portName);
    //发送串口打开失败的信号
    if(!this->port->open(QIODevice::ReadWrite))
    {
        emit  faild();
    }
    //在这里设置的都是串口的一些信息
    else
    {
        this->port->setBaudRate(9600, QSerialPort::AllDirections); //设置串口通信的波特率
        this->port->setDataBits(QSerialPort::Data8);//设置串口通信的数据位  8位
        this->port->setFlowControl(QSerialPort::NoFlowControl);//设置流控制  无
        this->port->setParity(QSerialPort::NoParity);//设置校验位   无
        this->port->setStopBits(QSerialPort::OneStop);//设置停止位    1
        //开启数据同步，并发送串口成功打开信号
        this->runComSync();
        emit succeed();
    }
}


//@@@@这里做了设备号的具体区分，但是并没有区分相关的传感器的不同方式，还是需要再进行一下区分
void rs485_connect::runComSync()
{
    int i = 0;
    QByteArray bytes;
    int dispalment_in0;    //用于存储转换后的整型数据
    double displament;     //计算得到的传感器数据
    while(true)
    {
        if(i > 1)
        {
            i = 0;   //目前只有两个设备，只需要进行两个设备的轮询即可
        }
        //发送ModbusRTU 查询指令，其中readCommand已经在构造函数中进行了初始化
        port->write(readCommand[i]);
        qDebug() << "发送" << readCommand[i];  //打印阀送的16位数据

        port->flush();
        port->waitForReadyRead(20);  //等待最多200ms以接收设备返回的数据（具体还需要进行调试和判断）

        //读取设备返回的数据
        bytes.resize(9);
        bytes = port->readAll();
        qDebug() << "接收" << bytes.toHex();


        //将四字节的数据转换成整数
        //3第三位是高位，直接左移8位，地位不需要进行移动，然后做或运算，(直接进行强制转换)
        dispalment_in0 = (bytes[3] << 8 ) | (bytes[4] & 0xFF);
        qDebug() << "转换成十进制后" << dispalment_in0;

        //这里要使用隐式转换实现，其中一个数成为double类型，或者直接使用其中一个数记性double类型的转换
        displament = static_cast<double>(dispalment_in0) / 819;
        qDebug() << "实际的输出值" << displament;

        //将位移传感器采集到的信息发送出去
        emit result(i, displament);
        i++;
    }
}





